package com.object.lq.utile;

import net.sourceforge.pinyin4j.PinyinHelper;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipOutputStream;

import static java.util.Objects.isNull;

@Component
public class VueConstructor {
    @Autowired
    private DataSource dataSource;
    private static final String VM_PATH = "templates/index.vue.vm";

    /**
     * 生成渲染页面和生成表字段的导入和导出
     *
     * @param response
     * @param tableNameEs    表名称 Es
     * @param templateNameEs 模板命名
     * @param requestUrl
     * @param path
     * @throws SQLException
     */
    public void contextLoads(HttpServletResponse response, String tableNameEs, String templateNameEs, String requestUrl, String path) throws SQLException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ZipOutputStream outZip = new ZipOutputStream(output);

        Connection connection = dataSource.getConnection();
        // 初始化模板引擎
        VelocityEngine velocityEngine = new VelocityEngine();
        velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        velocityEngine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        velocityEngine.init();

        velocityEngine.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
        velocityEngine.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
        // 设置变量，velocityContext是一个类似map的结构


        try {
            String[] tableNames = tableNameEs.split(",");
            String[] templateNames = templateNameEs.split(",");
            String[] qxmNamees = requestUrl.split(",");
            for (int i = 0; i < tableNames.length; i++) {
                String tableName = tableNames[i];
                String qxmName = qxmNamees[i];


                String templateName = templateNames[i];
                List<Table> tables = listTale(connection, tableName);
                List<Table> queryFieldNames = new ArrayList<>();
                for (Table item : tables) {
                    if (queryFieldNames.size() > 3) break;
                    if (item.getFieldName().contains("name") || item.getFieldName().contains("Name")) {
                        queryFieldNames.add(item);
                    }
                }

                VelocityContext velocityContext = new VelocityContext();
                velocityContext.put("list", tables);
                ArrayList<Table> tables1 = new ArrayList<>(tables);
                tables1.remove(0);
                velocityContext.put("lists", tables1);
                velocityContext.put("query", queryFieldNames);
                velocityContext.put("templateName", templateName);
                velocityContext.put("dataName", "基础模块");
                velocityContext.put("GLMK", "查询列表");
                velocityContext.put("add", "添加");
                velocityContext.put("TableName", underlineToCamel(tableName, true));
                velocityContext.put("apiName",velocityContext.get("TableName")+".ts");
                velocityContext.put("vueName",velocityContext.get("TableName")+".vue");
                velocityContext.put("requestUrl", qxmName);
                velocityContext.put("CapitalizeChinese", CapitalizeChinese(templateName + "管理"));
                velocityContext.put("updates", "更新成功");
                velocityContext.put("adds", "新增成功");
                velocityContext.put("deletes", "删除成功");
                createFile(velocityContext, outZip, templateName,path);
            }
            connection.close();
        //    IOUtils.closeQuietly(outZip);
//            byte[] data = output.toByteArray();
//            String fileName = URLEncoder.encode(templateNameEs, "UTF-8").replaceAll("\\+", "%20");
//            // 生成zip压缩包响应
//            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + ".zip\"");
//            response.addHeader("Content-Length", String.valueOf(data.length));
//            response.setContentType("application/octet-stream; charset=UTF-8");
//            IOUtils.write(data, response.getOutputStream());

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 拿表的字段信息
     *
     * @param connection
     * @param tableName
     * @return
     */
    private List<Table> listTale(Connection connection, String tableName) {

        List<Table> tables = new ArrayList<>();
        try {
            PreparedStatement statement = connection.prepareStatement("SELECT\n" +
                    " C.COLUMN_NAME AS 'fieldName',C.COLUMN_COMMENT comment,  C.CHARACTER_MAXIMUM_LENGTH AS 'size'\n" +
                    "FROM\n" +
                    "\n" +
                    "    information_schema.`TABLES` T\n" +
                    "LEFT JOIN information_schema.`COLUMNS` C ON T.TABLE_NAME = C.TABLE_NAME AND T.TABLE_SCHEMA = C.TABLE_SCHEMA\n" +
                    "where  T.TABLE_SCHEMA = '" + getCunntDatabaseName() + "' and T.TABLE_NAME=\"" + tableName + "\"   ORDER BY ordinal_position ");
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) {
                int size = resultSet.getInt(3) == 0 ? 20 : resultSet.getInt(3);
                String comment = resultSet.getString(2);
                comment = comment.contains(" ") ? comment.substring(0, comment.indexOf(" ")) : comment;
                tables.add(new Table(underlineToCamel(resultSet.getString(1), true), comment, size));
            }
            resultSet.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return tables;
    }

    /**
     * 下划线转驼峰法
     *
     * @param line       源字符串
     * @param smallCamel 大小驼峰,是否为小驼峰
     * @return 转换后的字符串
     */
    public static String underlineToCamel(String line, boolean smallCamel) {
        if (line == null || "".equals(line)) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        Pattern pattern = Pattern.compile("([A-Za-z\\d]+)(_)?");
        Matcher matcher = pattern.matcher(line);
        while (matcher.find()) {
            String word = matcher.group();
            sb.append(smallCamel && matcher.start() == 0 ? Character.toLowerCase(word.charAt(0)) : Character.toUpperCase(word.charAt(0)));
            int index = word.lastIndexOf('_');
            if (index > 0) {
                sb.append(word.substring(1, index).toLowerCase());
            } else {
                sb.append(word.substring(1).toLowerCase());
            }
        }
        return sb.toString();
    }


    /**
     * 读取本地模板,生成文件
     *
     * @param templatePath 模板路径
     * @param templateName 模板名称
     * @param outFilePath  生成文件路径
     */

    public static void getFile(
            String templatePath, String templateName, String outFilePath,
            VelocityContext context
    ) {
        try {
            // 获取模板
            Template tpl = Velocity.getTemplate(templateName, "UTF-8");
            // 创建输出流
            Writer writer = new PrintWriter(new FileOutputStream(new File(outFilePath)));
            // 模板与数据填充
            tpl.merge(context, writer);
            // 刷新数据
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 送请求， 将生成的模板文件
     *
     * @param
     * @param path
     * @throws IOException
     */
    public static void createFile(VelocityContext context, ZipOutputStream outZip, String templateName, String path)
            throws IOException {
        // 初始化模板引擎
        VelocityEngine velocityEngine = new VelocityEngine();
        velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        velocityEngine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        velocityEngine.init();
        //获取模板列表
        List<String> templates = getTemplates();
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = velocityEngine.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);
            // 添加数据
            File file =null;
            if (template.contains("ts")) {
                 String tsName=templateName.replaceAll("ts","ts");
                 file = new File(path+"\\apps\\web-antd\\src\\api\\" + tsName );
                //outZip.putNextEntry(new ZipEntry(context.get("TableName") + "/" + getFileName(template)));
            } else {
                file = new File(path+"\\apps\\web-antd\\src\\views\\" + templateName );
                //outZip.putNextEntry(new ZipEntry(templateName + "-" + getFileName(template)));
            }
            file.mkdirs();
            File file1 = new File(file.getPath() +  "\\" + getFileName(template,context));
            file1.createNewFile();
            OutputStream out = new BufferedOutputStream(new FileOutputStream(file1));
            IOUtils.write(sw.toString(), out, "UTF-8");
            out.close();
            IOUtils.closeQuietly(sw);
        }

    }

    /**
     * 获取文件名
     */

    private static String getFileName(String template, VelocityContext context) {
        if (template.startsWith("templates/index.ts")){
             return (String) context.get("apiName");
        }
        return (String) context.get("vueName");
    }

    /**
     * 获取模板
     */
    private static List<String> getTemplates() {
        List<String> templates = new ArrayList();
        // 后端相关模板
        templates.add("templates/index.vue.vm");
        templates.add("templates/index.ts.vm");
        return templates;
    }

    /**
     * 大写中文
     *
     * @param c
     * @return
     */
    public static String CapitalizeChinese(String c) {
        char b;
        String msg = "";
        int a = c.length();
        for (int k = 0; k < a; k++) {
            b = c.charAt(k);
            String d = String.valueOf(b);
            String str = getPinYinHeadChar(d);
            String s = str.toUpperCase();
            String g = s;
            char h;
            int j = g.length();
            for (int y = 0; y <= 0; y++) {
                h = g.charAt(0);
                msg += h;
            }
        }
        return msg;
    }

    /**
     * 提取每个汉字的首字母(大写)
     *
     * @param str
     * @return
     */
    public static String getPinYinHeadChar(String str) {
        if (isNull(str)) {
            return "";
        }
        String convert = "";
        for (int j = 0; j < str.length(); j++) {
            char word = str.charAt(j);
            // 提取汉字的首字母
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
            if (pinyinArray != null) {
                convert += pinyinArray[0].charAt(0);
            } else {
                convert += word;
            }
        }

        convert = string2AllTrim(convert);
        return convert.toUpperCase();
    }

    /**
     * 去掉字符串包含的所有空格
     *
     * @param value
     * @return
     */
    public static String string2AllTrim(String value) {
        if (isNull(value)) {
            return "";
        }
        return value.trim().replace(" ", "");
    }


    @Value("${spring.datasource.url}")
    private String url;

    /**
     * 获取当前数据库的名称
     *
     * @return
     */
    private String getCunntDatabaseName() {
        String[] strings = url.substring(0, url.indexOf("?")).split("/");
        System.out.println(strings[strings.length - 1]);
        return strings[strings.length - 1];
    }


}
